/*
 * $Id:   Broadcom SDK $
 *
 * $Copyright: Copyright 2011 Broadcom Corporation.
 * This program is the proprietary software of Broadcom Corporation
 * and/or its licensors, and may only be used, duplicated, modified
 * or distributed pursuant to the terms and conditions of a separate,
 * written license agreement executed between you and Broadcom
 * (an "Authorized License").  Except as set forth in an Authorized
 * License, Broadcom grants no license (express or implied), right
 * to use, or waiver of any kind with respect to the Software, and
 * Broadcom expressly reserves all rights in and to the Software
 * and all intellectual property rights therein.  IF YOU HAVE
 * NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS SOFTWARE
 * IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
 * ALL USE OF THE SOFTWARE.  
 *  
 * Except as expressly set forth in the Authorized License,
 *  
 * 1.     This program, including its structure, sequence and organization,
 * constitutes the valuable trade secrets of Broadcom, and you shall use
 * all reasonable efforts to protect the confidentiality thereof,
 * and to use this information only in connection with your use of
 * Broadcom integrated circuit products.
 *  
 * 2.     TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS
 * PROVIDED "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
 * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
 * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE.  BROADCOM SPECIFICALLY
 * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
 * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
 * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
 * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING
 * OUT OF USE OR PERFORMANCE OF THE SOFTWARE.
 * 
 * 3.     TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL
 * BROADCOM OR ITS LICENSORS BE LIABLE FOR (i) CONSEQUENTIAL,
 * INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY DAMAGES WHATSOEVER
 * ARISING OUT OF OR IN ANY WAY RELATING TO YOUR USE OF OR INABILITY
 * TO USE THE SOFTWARE EVEN IF BROADCOM HAS BEEN ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES; OR (ii) ANY AMOUNT IN EXCESS OF
 * THE AMOUNT ACTUALLY PAID FOR THE SOFTWARE ITSELF OR USD 1.00,
 * WHICHEVER IS GREATER. THESE LIMITATIONS SHALL APPLY NOTWITHSTANDING
 * ANY FAILURE OF ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.$
 *
 * File:     port.c
 * Purpose:
 *
 */

#include <bcm/types.h>
#include <bcm/port.h>
#include <bcm/error.h>
#include <bcm_int/tk371x_dispatch.h>
#include <bcm_int/ea/port.h>
#include <bcm_int/ea/tk371x/port.h>
#include <soc/types.h>
#include <soc/debug.h>
#include <soc/ea/onu.h>
#include <soc/drv.h>


#define DRV_TK371X_PORT_STATUS_AUTONEG_ENABLE	2
#define DRV_TK371X_PORT_STATUS_AUTONEG_DISABLE	1


/*
 * Function:
 *  bcm_tk371x_port_loopback_get
 * Purpose:
 *  Recover the current loopback operation for the specified port.
 * Parameters:
 *  unit - EA tk371x Unit #.
 *  port - tk371x port #.
 *  loopback - (OUT) one of:
 *      BCM_PORT_LOOPBACK_NONE
 *      BCM_PORT_LOOPBACK_MAC
 *      BCM_PORT_LOOPBACK_PHY
 * Returns:
 *  BCM_E_NONE
 *  BCM_E_XXX
 */
int
bcm_tk371x_port_loopback_get(
		int unit,
		bcm_port_t port,
		int *loopback)
{
    if (0 == SOC_UNIT_VALID((unit))){
    	return BCM_E_UNIT;
    }
    if (0 == SOC_PORT_VALID(unit, port)){
#if _BCM_EA_PORT_DEBUG
        soc_cm_print("Return value: BCM_E_PORT: invalid PORT : %d\n", (port));
#endif
        return BCM_E_PORT;
    }
	if (port < _BCM_TK371X_UNI_PORT_BASE || port >= _BCM_TK371X_LLID_PORT_BASE){
		return BCM_E_UNAVAIL;
	}
	return BCM_E_UNAVAIL;
}

/*
 * Function:
 *  bcm_tk371x_port_loopback_set
 * Purpose:
 *  Setting the speed for a given port
 * Parameters:
 *  unit - EA tk371x Unit #.
 *  port - EA tk371x port #.
 *  loopback - one of:
 *      BCM_PORT_LOOPBACK_NONE
 *      BCM_PORT_LOOPBACK_MAC
 *      BCM_PORT_LOOPBACK_PHY
 * Returns:
 *  BCM_E_NONE
 *  BCM_E_XXX
 */
int
bcm_tk371x_port_loopback_set(
		int unit,
		bcm_port_t port,
		int loopback){
    if (0 == SOC_UNIT_VALID((unit))){
    	return BCM_E_UNIT;
    }
    if (0 == SOC_PORT_VALID(unit, port)){
#if _BCM_EA_PORT_DEBUG
        soc_cm_print("Return value: BCM_E_PORT: invalid PORT : %d\n", (port));
#endif
        return BCM_E_PORT;
    }
	if (port < _BCM_TK371X_UNI_PORT_BASE || port >= _BCM_TK371X_LLID_PORT_BASE){
		return BCM_E_UNAVAIL;
	}
	return BCM_E_UNAVAIL;
}


/*
 * Function:
 *  bcm_tk371x_port_pause_get
 * Purpose:
 *  Get the pause state for a given port
 * Parameters:
 *  unit - tk371x Unit #.
 *  port - tk371x port #.
 *  pause_tx - (OUT) Boolean value
 *  pause_rx - (OUT) Boolean value
 * Returns:
 *  BCM_E_NONE
 *  BCM_E_XXX
 */
int
bcm_tk371x_port_pause_get(
		int unit,
		bcm_port_t port,
		int *pause_tx,
		int *pause_rx)
{
    if (0 == SOC_UNIT_VALID((unit))){
    	return BCM_E_UNIT;
    }
    if (0 == SOC_PORT_VALID(unit, port)){
#if _BCM_EA_PORT_DEBUG
        soc_cm_print("Return value: BCM_E_PORT: invalid PORT : %d\n", (port));
#endif
        return BCM_E_PORT;
    }
	if (port < _BCM_TK371X_UNI_PORT_BASE || port >= _BCM_TK371X_LLID_PORT_BASE){
		return BCM_E_UNAVAIL;
	}
	return BCM_E_UNAVAIL;
}


/*
 * Function:
 *  bcm_tk371x_port_pause_set
 * Purpose:
 *  Set the pause state for a given port
 * Parameters:
 *  unit - tk371x Unit #.
 *  port - tk371x port #.
 *  pause_tx - Boolean value
 *  pause_rx - Boolean value
 * Returns:
 *  BCM_E_NONE
 *  BCM_E_XXX
 * Notes:
 *  Symmetric pause requires the two "pause" values to be the same.
 */
int
bcm_tk371x_port_pause_set(
		int unit,
		bcm_port_t port,
		int pause_tx,
		int pause_rx)
{
    if (0 == SOC_UNIT_VALID((unit))){
    	return BCM_E_UNIT;
    }
    if (0 == SOC_PORT_VALID(unit, port)){
#if _BCM_EA_PORT_DEBUG
        soc_cm_print("Return value: BCM_E_PORT: invalid PORT : %d\n", (port));
#endif
        return BCM_E_PORT;
    }
	if (port < _BCM_TK371X_UNI_PORT_BASE || port >= _BCM_TK371X_LLID_PORT_BASE){
		return BCM_E_UNAVAIL;
	}
	return BCM_E_UNAVAIL;
}

/*
 * Function:
 *      bcm_tk371x_port_medium_get
 * Description:
 *      Get the medium-specific configuration for a combo port
 * Parameters:
 *      unit     - Device number
 *      port     - Port number
 *      medium   - The medium (BCM_PORT_MEDIUM_COPPER or BCM_PORT_MEDIUM_FIBER)
 *                 to get the config for
 *      config   - per-medium configuration
 * Return Value:
 *      BCM_E_XXX
 */
int
bcm_tk371x_port_medium_get(
		int unit,
		bcm_port_t port,
		bcm_port_medium_t *medium)
{
    if (0 == SOC_UNIT_VALID((unit))){
    	return BCM_E_UNIT;
    }
    if (0 == SOC_PORT_VALID(unit, port)){
#if _BCM_EA_PORT_DEBUG
        soc_cm_print("Return value: BCM_E_PORT: invalid PORT : %d\n", (port));
#endif
        return BCM_E_PORT;
    }
	if (port < _BCM_TK371X_UNI_PORT_BASE || port >= _BCM_TK371X_LLID_PORT_BASE){
		return BCM_E_UNAVAIL;
	}
	return BCM_E_UNAVAIL;
}

/*
 * Function:
 *  bcm_tk371x_port_mdix_get
 * Description:
 *  Get the Auto-MDIX mode of a port/PHY
 * Parameters:
 *  unit - Device number
 *  port - Port number
 *  mode - (Out) One of:
 *            BCM_PORT_MDIX_AUTO
 *          Enable auto-MDIX when autonegotiation is enabled
 *            BCM_PORT_MDIX_FORCE_AUTO
 *          Enable auto-MDIX always
 *      BCM_PORT_MDIX_NORMAL
 *          Disable auto-MDIX
 *      BCM_PORT_MDIX_XOVER
 *          Disable auto-MDIX, and swap cable pairs
 * Return Value:
 *  BCM_E_UNAVAIL - feature unsupported by hardware
 *  BCM_E_XXX - other error
 */
int
bcm_tk371x_port_mdix_get(
		int unit,
		bcm_port_t port,
		bcm_port_mdix_t *midx)
{
    if (0 == SOC_UNIT_VALID((unit))){
    	return BCM_E_UNIT;
    }
    if (0 == SOC_PORT_VALID(unit, port)){
#if _BCM_EA_PORT_DEBUG
        soc_cm_print("Return value: BCM_E_PORT: invalid PORT : %d\n", (port));
#endif
        return BCM_E_PORT;
    }
	if (port < _BCM_TK371X_UNI_PORT_BASE || port >= _BCM_TK371X_LLID_PORT_BASE){
		return BCM_E_UNAVAIL;
	}
	return BCM_E_UNAVAIL;
}

/*
 * Function:
 *  bcm_port_mdix_set
 * Description:
 *  Set the Auto-MDIX mode of a port/PHY
 * Parameters:
 *  unit - Device number
 *  port - Port number
 *  mode - One of:
 *            BCM_PORT_MDIX_AUTO
 *          Enable auto-MDIX when autonegotiation is enabled
 *            BCM_PORT_MDIX_FORCE_AUTO
 *          Enable auto-MDIX always
 *      BCM_PORT_MDIX_NORMAL
 *          Disable auto-MDIX
 *      BCM_PORT_MDIX_XOVER
 *          Disable auto-MDIX, and swap cable pairs
 * Return Value:
 *  BCM_E_UNAVAIL - feature unsupported by hardware
 *  BCM_E_XXX - other error
 */
int
bcm_tk371x_port_mdix_set(
		int unit,
		bcm_port_t port,
		bcm_port_mdix_t mdix)
{
    if (0 == SOC_UNIT_VALID((unit))){
    	return BCM_E_UNIT;
    }
    if (0 == SOC_PORT_VALID(unit, port)){
#if _BCM_EA_PORT_DEBUG
        soc_cm_print("Return value: BCM_E_PORT: invalid PORT : %d\n", (port));
#endif
        return BCM_E_PORT;
    }
	if (port < _BCM_TK371X_UNI_PORT_BASE || port >= _BCM_TK371X_LLID_PORT_BASE){
		return BCM_E_UNAVAIL;
	}
	return BCM_E_UNAVAIL;
}

/*
 * Function:
 *  bcm_tk371x_port_mdix_status_get
 * Description:
 *  Get the current MDIX status on a port/PHY
 * Parameters:
 *  unit    - Device number
 *  port    - Port number
 *  status  - (OUT) One of:
 *            BCM_PORT_MDIX_STATUS_NORMAL
 *          Straight connection
 *            BCM_PORT_MDIX_STATUS_XOVER
 *          Crossover has been performed
 * Return Value:
 *  BCM_E_UNAVAIL - feature unsupported by hardware
 *  BCM_E_XXX - other error
 */
int
bcm_tk371x_port_mdix_status_get(
		int unit,
		bcm_port_t port,
		bcm_port_mdix_status_t *midx_status)
{
    if (0 == SOC_UNIT_VALID((unit))){
    	return BCM_E_UNIT;
    }
    if (0 == SOC_PORT_VALID(unit, port)){
#if _BCM_EA_PORT_DEBUG
        soc_cm_print("Return value: BCM_E_PORT: invalid PORT : %d\n", (port));
#endif
        return BCM_E_PORT;
    }
	if (port < _BCM_TK371X_UNI_PORT_BASE || port >= _BCM_TK371X_LLID_PORT_BASE){
		return BCM_E_UNAVAIL;
	}
	return BCM_E_UNAVAIL;
}

/*
 * Function:
 *  bcm_tk371x_port_interface_get
 * Purpose:
 *  Getting the interface type of a port
 * Parameters:
 *  unit - tk371x Unit #.
 *  port - tk371x port #.
 *  intf - (OUT) BCM_PORT_IF_*
 * Returns:
 *  BCM_E_NONE
 *  BCM_E_XXX
 * Notes:
 *      WARNING: assumes BCM_PORT_IF_* matches SOC_PORT_IF_*
 */

int
bcm_tk371x_port_interface_get(
		int unit,
		bcm_port_t port,
		bcm_port_if_t *interface)
{
    if (0 == SOC_UNIT_VALID((unit))){
    	return BCM_E_UNIT;
    }
    if (0 == SOC_PORT_VALID(unit, port)){
#if _BCM_EA_PORT_DEBUG
        soc_cm_print("Return value: BCM_E_PORT: invalid PORT : %d\n", (port));
#endif
        return BCM_E_PORT;
    }
	if (port < _BCM_TK371X_UNI_PORT_BASE || port >= _BCM_TK371X_LLID_PORT_BASE){
		return BCM_E_UNAVAIL;
	}

	if (port == 1){
		*interface = BCM_PORT_ABILITY_INTERFACE_GMII;
	}
	if (port == 2){
		*interface = BCM_PORT_ABILITY_INTERFACE_MII;
	}
	return BCM_E_UNAVAIL;
}


/*
 * Function:
 *  bcm_tk371x_port_interface_set
 * Purpose:
 *  Setting the interface type for a given port
 * Parameters:
 *  unit - tk371x Unit #.
 *  port - tk371x port #.
 *  if - BCM_PORT_IF_*
 * Returns:
 *  BCM_E_NONE
 *  BCM_E_XXX
 * Notes:
 *      WARNING: assumes BCM_PORT_IF_* matches SOC_PORT_IF_*
 */
int
bcm_tk371x_port_interface_set(
		int unit,
		bcm_port_t port,
		bcm_port_if_t interface)
{
    if (0 == SOC_UNIT_VALID((unit))){
    	return BCM_E_UNIT;
    }
    if (0 == SOC_PORT_VALID(unit, port)){
#if _BCM_EA_PORT_DEBUG
        soc_cm_print("Return value: BCM_E_PORT: invalid PORT : %d\n", (port));
#endif
        return BCM_E_PORT;
    }
	if (port < _BCM_TK371X_UNI_PORT_BASE || port >= _BCM_TK371X_LLID_PORT_BASE){
		return BCM_E_UNAVAIL;
	}
	return BCM_E_UNAVAIL;
}

/*
 * Function:
 *  bcm_tk371x_port_master_get
 * Purpose:
 *  Getting the master status of the port
 * Parameters:
 *  unit - tk371x Unit #.
 *  port - tk371x port #.
 *  ms - (OUT) BCM_PORT_MS_*
 * Returns:
 *  BCM_E_NONE
 *  BCM_E_XXX
 * Notes:
 *      WARNING: assumes BCM_PORT_MS_* matches SOC_PORT_MS_*
 */
int
bcm_tk371x_port_master_get(
		int unit,
		bcm_port_t port,
		int *master)
{
    if (0 == SOC_UNIT_VALID((unit))){
    	return BCM_E_UNIT;
    }
    if (0 == SOC_PORT_VALID(unit, port)){
#if _BCM_EA_PORT_DEBUG
        soc_cm_print("Return value: BCM_E_PORT: invalid PORT : %d\n", (port));
#endif
        return BCM_E_PORT;
    }
	if (port < _BCM_TK371X_UNI_PORT_BASE || port >= _BCM_TK371X_LLID_PORT_BASE){
		return BCM_E_UNAVAIL;
	}
	return BCM_E_UNAVAIL;
}

/*
 * Function:
 *  bcm_tk371x_port_master_set
 * Purpose:
 *  Setting the master status for a given port
 * Parameters:
 *  unit - tk371x Unit #.
 *  port - tk371x port #.
 *  ms - BCM_PORT_MS_*
 * Returns:
 *  BCM_E_NONE
 *  BCM_E_XXX
 * Notes:
 *  Ignored if not supported on port.
 *      WARNING: assumes BCM_PORT_MS_* matches SOC_PORT_MS_*
 */
int
bcm_tk371x_port_master_set(
		int unit,
		bcm_port_t port,
		int master)
{
    if (0 == SOC_UNIT_VALID((unit))){
    	return BCM_E_UNIT;
    }
    if (0 == SOC_PORT_VALID(unit, port)){
#if _BCM_EA_PORT_DEBUG
        soc_cm_print("Return value: BCM_E_PORT: invalid PORT : %d\n", (port));
#endif
        return BCM_E_PORT;
    }
	if (port < _BCM_TK371X_UNI_PORT_BASE || port >= _BCM_TK371X_LLID_PORT_BASE){
		return BCM_E_UNAVAIL;
	}
	return BCM_E_UNAVAIL;
}

/*
 * Function:
 *      bcm_tk371x_port_ability_advert_get
 * Purpose:
 *      Retrieve the local port advertisement for autonegotiation.
 * Parameters:
 *      unit - tk371x Unit #.
 *      port - tk371x port #.
 *      ability_mask - (OUT) Local advertisement.
 * Returns:
 *      BCM_E_NONE
 *      BCM_E_XXX
 */
int
bcm_tk371x_port_ability_advert_get(
		int unit,
		bcm_port_t port,
		bcm_port_ability_t *ability)
{
    if (0 == SOC_UNIT_VALID((unit))){
    	return BCM_E_UNIT;
    }
    if (0 == SOC_PORT_VALID(unit, port)){
#if _BCM_EA_PORT_DEBUG
        soc_cm_print("Return value: BCM_E_PORT: invalid PORT : %d\n", (port));
#endif
        return BCM_E_PORT;
    }
	if (port < _BCM_TK371X_UNI_PORT_BASE || port >= _BCM_TK371X_LLID_PORT_BASE){
		return BCM_E_UNAVAIL;
	}
	return BCM_E_UNAVAIL;
}

/*
 * Function:
 *      bcm_tk371x_port_ability_advert_set
 * Purpose:
 *      Set the local port advertisement for autonegotiation.
 * Parameters:
 *      unit - tk371x Unit #.
 *      port - tk371x port #.
 *      ability_mask - Local advertisement.
 * Returns:
 *      BCM_E_NONE
 *      BCM_E_XXX
 * Notes:
 *      This call MAY NOT restart autonegotiation (depending on the phy).
 *      To do that, follow this call with bcm_port_autoneg_set(TRUE).
 */
int
bcm_tk371x_port_ability_advert_set(
		int unit,
		bcm_port_t port,
		bcm_port_ability_t *ability)
{
    if (0 == SOC_UNIT_VALID((unit))){
    	return BCM_E_UNIT;
    }
    if (0 == SOC_PORT_VALID(unit, port)){
#if _BCM_EA_PORT_DEBUG
        soc_cm_print("Return value: BCM_E_PORT: invalid PORT : %d\n", (port));
#endif
        return BCM_E_PORT;
    }
	if (port < _BCM_TK371X_UNI_PORT_BASE || port >= _BCM_TK371X_LLID_PORT_BASE){
		return BCM_E_UNAVAIL;
	}
	return BCM_E_UNAVAIL;
}

/*
 * Function:
 *  bcm_tk371x_port_ability_get
 * Purpose:
 *  Retrieve the local port abilities.
 * Parameters:
 *  unit - tk371x Unit #.
 *  port - tk371x port #.
 *  ability_mask - (OUT) Mask of BCM_PORT_ABIL_ values indicating the
 *      ability of the MAC/PHY.
 * Returns:
 *  BCM_E_NONE
 *  BCM_E_XXX
 */

int
bcm_tk371x_port_ability_get(
		int unit,
		bcm_port_t port,
		bcm_port_abil_t *abil)
{
    if (0 == SOC_UNIT_VALID((unit))){
    	return BCM_E_UNIT;
    }
    if (0 == SOC_PORT_VALID(unit, port)){
#if _BCM_EA_PORT_DEBUG
        soc_cm_print("Return value: BCM_E_PORT: invalid PORT : %d\n", (port));
#endif
        return BCM_E_PORT;
    }
	if (port < _BCM_TK371X_UNI_PORT_BASE || port >= _BCM_TK371X_LLID_PORT_BASE){
		return BCM_E_UNAVAIL;
	}
	return BCM_E_UNAVAIL;
}

/*
 * Function:
 *      bcm_tk371x_port_ability_remote_get
 * Purpose:
 *      Retrieve the local port advertisement for autonegotiation.
 * Parameters:
 *      unit - tk371x Unit #.
 *      port - tk371x port #.
 *      ability_mask - (OUT) Remote advertisement.
 * Returns:
 *      BCM_E_NONE
 *      BCM_E_XXX
 */
int
bcm_tk371x_port_ability_remote_get(
		int unit,
		bcm_port_t port,
		bcm_port_ability_t *ability)
{
    if (0 == SOC_UNIT_VALID((unit))){
    	return BCM_E_UNIT;
    }
    if (0 == SOC_PORT_VALID(unit, port)){
#if _BCM_EA_PORT_DEBUG
        soc_cm_print("Return value: BCM_E_PORT: invalid PORT : %d\n", (port));
#endif
        return BCM_E_PORT;
    }
	if (port < _BCM_TK371X_UNI_PORT_BASE || port >= _BCM_TK371X_LLID_PORT_BASE){
		return BCM_E_UNAVAIL;
	}
	return BCM_E_UNAVAIL;
}

/*
 * Function:
 *      bcm_tk371x_port_ability_local_get
 * Purpose:
 *      Retrieve the local port abilities.
 * Parameters:
 *      unit - Tk371x Unit #.
 *      port - tk371x port #.
 *      ability_mask - (OUT) Mask of BCM_PORT_ABIL_ values indicating the
 *              ability of the MAC/PHY.
 * Returns:
 *      BCM_E_NONE
 *      BCM_E_XXX
 */
int
bcm_tk371x_port_ability_local_get(
		int unit,
		bcm_port_t port,
		bcm_port_ability_t *port_ability)
{
    if (0 == SOC_UNIT_VALID((unit))){
    	return BCM_E_UNIT;
    }
    if (0 == SOC_PORT_VALID(unit, port)){
#if _BCM_EA_PORT_DEBUG
        soc_cm_print("Return value: BCM_E_PORT: invalid PORT : %d\n", (port));
#endif
        return BCM_E_PORT;
    }
	if (port < _BCM_TK371X_UNI_PORT_BASE || port >= _BCM_TK371X_LLID_PORT_BASE){
		return BCM_E_UNAVAIL;
	}

	if (port == 1){
		port_ability->speed_half_duplex = _SHR_PA_ABILITY_NONE;
		port_ability->speed_full_duplex = BCM_PORT_ABILITY_2500MB;
		port_ability->pause =
				BCM_PORT_ABILITY_PAUSE | BCM_PORT_ABILITY_PAUSE_ASYMM;
		port_ability->interface =
				BCM_PORT_ABILITY_INTERFACE_GMII | BCM_PORT_ABILITY_INTERFACE_TBI;
	}
	if (port == 2){
		port_ability->speed_half_duplex =
				BCM_PORT_ABILITY_10MB | BCM_PORT_ABILITY_100MB;
		port_ability->speed_full_duplex =
				BCM_PORT_ABILITY_10MB | BCM_PORT_ABILITY_100MB;
		port_ability->pause =
				BCM_PORT_ABILITY_PAUSE | BCM_PORT_ABILITY_PAUSE_ASYMM;
		port_ability->interface =
				BCM_PORT_ABILITY_INTERFACE_MII;
	}
	port_ability->medium = _SHR_PA_ABILITY_NONE;
	port_ability->loopback = BCM_PORT_ABILITY_LB_MAC;
	port_ability->encap = BCM_PA_ENCAP_IEEE;

	return BCM_E_UNAVAIL;
}

int
bcm_tk371x_port_ability_local_set(
		int unit,
		bcm_port_t port,
		bcm_port_ability_t port_ability)
{
    if (0 == SOC_UNIT_VALID((unit))){
    	return BCM_E_UNIT;
    }
    if (0 == SOC_PORT_VALID(unit, port)){
#if _BCM_EA_PORT_DEBUG
        soc_cm_print("Return value: BCM_E_PORT: invalid PORT : %d\n", (port));
#endif
        return BCM_E_PORT;
    }
	if (port < _BCM_TK371X_UNI_PORT_BASE || port >= _BCM_TK371X_LLID_PORT_BASE){
		return BCM_E_UNAVAIL;
	}
	return BCM_E_UNAVAIL;
}


/*
 * Function:
 *  bcm_tk371x_port_advert_get
 * Purpose:
 *  Retrieve the local port advertisement for autonegotiation.
 * Parameters:
 *  unit - EA Unit #.
 *  port - EA port #.
 *  ability_mask - (OUT) Local advertisement.
 * Returns:
 *  BCM_E_NONE
 *  BCM_E_XXX
 */
int
bcm_tk371x_port_advert_get(
		int unit,
		bcm_port_t port,
		bcm_port_abil_t *abilty)
{
    if (0 == SOC_UNIT_VALID((unit))){
    	return BCM_E_UNIT;
    }
    if (0 == SOC_PORT_VALID(unit, port)){
#if _BCM_EA_PORT_DEBUG
        soc_cm_print("Return value: BCM_E_PORT: invalid PORT : %d\n", (port));
#endif
        return BCM_E_PORT;
    }
	if (port < _BCM_TK371X_UNI_PORT_BASE || port >= _BCM_TK371X_LLID_PORT_BASE){
		return BCM_E_UNAVAIL;
	}

	*abilty = 0;
	if (port == 1){
		*abilty |= BCM_PORT_ABIL_10MB_HD;
		*abilty |= BCM_PORT_ABIL_10MB_FD;
		*abilty |= BCM_PORT_ABIL_100MB_HD;
		*abilty |= BCM_PORT_ABIL_100MB_FD;
		*abilty |= BCM_PORT_ABIL_1000MB_FD;
		*abilty |= BCM_PORT_ABIL_GMII;
		*abilty |= BCM_PORT_ABIL_PAUSE_TX;
		*abilty |= BCM_PORT_ABIL_PAUSE_RX;
	}
	if (port == 2){
		*abilty |= BCM_PORT_ABIL_10MB_HD;
		*abilty |= BCM_PORT_ABIL_10MB_FD;
		*abilty |= BCM_PORT_ABIL_100MB_HD;
		*abilty |= BCM_PORT_ABIL_100MB_FD;
		*abilty |= BCM_PORT_ABIL_MII;
		*abilty |= BCM_PORT_ABIL_PAUSE_TX;
		*abilty |= BCM_PORT_ABIL_PAUSE_RX;
	}
	return BCM_E_UNAVAIL;

}

/*
 * Function:
 *  bcm_tk371x_port_advert_remote_get
 * Purpose:
 *  Retrieve the local port advertisement for autonegotiation.
 * Parameters:
 *  unit - EA Unit #.
 *  port - EA port #.
 *  ability_mask - (OUT) Remote advertisement.
 * Returns:
 *  BCM_E_NONE
 *  BCM_E_XXX
 */

int
bcm_tk371x_port_advert_remote_get(
		int unit,
		bcm_port_t port,
		bcm_port_abil_t *abil)
{
    if (0 == SOC_UNIT_VALID((unit))){
    	return BCM_E_UNIT;
    }
    if (0 == SOC_PORT_VALID(unit, port)){
#if _BCM_EA_PORT_DEBUG
        soc_cm_print("Return value: BCM_E_PORT: invalid PORT : %d\n", (port));
#endif
        return BCM_E_PORT;
    }
	if (port < _BCM_TK371X_UNI_PORT_BASE || port >= _BCM_TK371X_LLID_PORT_BASE){
		return BCM_E_UNAVAIL;
	}
	return BCM_E_UNAVAIL;
}

/*
 * Function:
 *  bcm_tk371x_port_advert_set
 * Purpose:
 *  Set the local port advertisement for autonegotiation.
 * Parameters:
 *  unit - EA Unit #.
 *  port - EA port #.
 *  ability_mask - Local advertisement.
 * Returns:
 *  BCM_E_NONE
 *  BCM_E_XXX
 * Notes:
 *  Does NOT restart autonegotiation.
 *  To do that, follow this call with bcm_port_autoneg_set(TRUE).
 */
int
bcm_tk371x_port_advert_set(
		int unit,
		bcm_port_t port,
		bcm_port_abil_t abilty)
{
    if (0 == SOC_UNIT_VALID((unit))){
    	return BCM_E_UNIT;
    }
    if (0 == SOC_PORT_VALID(unit, port)){
#if _BCM_EA_PORT_DEBUG
        soc_cm_print("Return value: BCM_E_PORT: invalid PORT : %d\n", (port));
#endif
        return BCM_E_PORT;
    }
	if (port < _BCM_TK371X_UNI_PORT_BASE || port >= _BCM_TK371X_LLID_PORT_BASE){
		return BCM_E_UNAVAIL;
	}
	return BCM_E_UNAVAIL;
}

/*
 * Function:
 *  bcm_tk371x_port_autoneg_get
 * Purpose:
 *  Get the autonegotiation state of the port
 * Parameters:
 *  unit - EA Unit #.
 *  port - EA port #.
 *  autoneg - (OUT) Boolean value
 * Returns:
 *  BCM_E_NONE
 *  BCM_E_XXX
 */
int bcm_tk371x_port_autoneg_get(
	    int unit,
	    bcm_port_t port,
	    int *autoneg)
{
    int         rv = BCM_E_NONE;
    int         drv_act_value = 0;

#if _BCM_EA_PORT_DEBUG
    soc_cm_print("BCM API : bcm_tk371x_port_autoneg_get..\n");
    soc_cm_print("bcm_tk371x_port_autoneg_get, unit = %d, port = %d\n", unit, port);
#endif
    if (0 == SOC_UNIT_VALID((unit))){
    	return BCM_E_UNIT;
    }
    if (0 == SOC_PORT_VALID(unit, port)){
#if _BCM_EA_PORT_DEBUG
        soc_cm_print("Return value: BCM_E_PORT: invalid PORT : %d\n", (port));
#endif
        return BCM_E_PORT;
    }

    /* Note :
     *   - port_get(DRV_PORT_PROP_AUTONEG) will return AN status.
     *      So we need to trnslate status into boolean.
     */
    rv = _bcm_ea_port_autoneg_get(unit, port, &drv_act_value);
    *autoneg = (drv_act_value == DRV_TK371X_PORT_STATUS_AUTONEG_ENABLE) ?
                    TRUE : FALSE;
#if _BCM_EA_PORT_DEBUG
    soc_cm_print("_bcm_ea_port_autoneg_get, rv=%d, drv_act_value=%d\n",
    		rv, drv_act_value);
    soc_cm_print("*autoneg=%d\n", *autoneg);
#endif
    return rv;
}

/*
 * Function:
 *  bcm_tk371x_port_autoneg_set
 * Purpose:
 *  Set the autonegotiation state for a given port
 * Parameters:
 *  unit - EA Unit #.
 *  port - EA port #.
 *  autoneg - Boolean value
 * Returns:
 *  BCM_E_NONE
 *  BCM_E_XXX
 */
int
bcm_tk371x_port_autoneg_set(
          int unit,
          bcm_port_t port,
          int autoneg)
{
      int rv;

#if _BCM_EA_PORT_DEBUG
      soc_cm_print("BCM API : bcm_tk371x_port_autoneg_set..\n");
#endif
      if (0 == SOC_UNIT_VALID((unit))){
          return BCM_E_UNIT;
      }
      if (0 == SOC_PORT_VALID(unit, port)){
#if _BCM_EA_PORT_DEBUG
          soc_cm_print("Return value: BCM_E_PORT, invaild PORT : %d\n", (port));
#endif
          return BCM_E_PORT;
      }
      if (TRUE != autoneg && FALSE != autoneg){
#if _BCM_EA_PORT_DEBUG
    	  soc_cm_print("Return value: BCM_E_PARAM, autoneg=%d\n", autoneg);
#endif
          return BCM_E_PARAM;
      }
      rv = _bcm_ea_port_autoneg_set(unit, port, autoneg);

      return rv;
}

/* General routines on which most port routines are built */

/*
 * Function:
 *  bcm_tk371x_port_config_get
 * Purpose:
 *  Get port configuration of a device
 * Parameters:
 *  unit - EA Unit #.
 *  config - (OUT) Structure returning configuration
 * Returns:
 *  BCM_E_XXX
 */
int
bcm_tk371x_port_config_get(
		int unit,
		bcm_port_config_t *config)
{
#if _BCM_EA_PORT_DEBUG
	char pbuf[SOC_PBMP_FMT_LEN + 1];

    soc_cm_print("BCM API : bcm_tk371x_port_config_get()..\n");
#endif
    if (0 == SOC_UNIT_VALID(unit)){
    	return BCM_E_UNIT;
    }
    if (NULL == config){
    	return BCM_E_PARAM;
    }
#if _BCM_EA_PORT_DEBUG
	soc_cm_print("before call soc marcos:\n");
    sal_memset(pbuf, 0, sizeof(pbuf));
    SOC_PBMP_FMT(config->fe, pbuf);
    soc_cm_print("config->fe=%s\n", pbuf);
    SOC_PBMP_FMT(config->ge, pbuf);
    soc_cm_print("config->ge=%s\n", pbuf);
    SOC_PBMP_FMT(config->port, pbuf);
    soc_cm_print("config->port=%s\n", pbuf);
    SOC_PBMP_FMT(config->all, pbuf);
    soc_cm_print("config->all=%s\n", pbuf);
    SOC_PBMP_FMT(config->llid, pbuf);
    soc_cm_print("config->llid=%s\n", pbuf);
    SOC_PBMP_FMT(config->pon, pbuf);
    soc_cm_print("config->pon=%s\n", pbuf);
#endif
	config->fe      = PBMP_FE_ALL(unit);
    config->ge      = PBMP_GE_ALL(unit);
    config->port    = PBMP_PORT_ALL(unit);
    config->all     = PBMP_ALL(unit);
    config->llid	= PBMP_LLID_ALL(unit);
    config->pon		= PBMP_PON_ALL(unit);
#if _BCM_EA_PORT_DEBUG
    soc_cm_print("after call soc marcos:\n");
    sal_memset(pbuf, 0, sizeof(pbuf));
    SOC_PBMP_FMT(config->fe, pbuf);
    soc_cm_print("config->fe=%s\n", pbuf);
    SOC_PBMP_FMT(config->ge, pbuf);
    soc_cm_print("config->ge=%s\n", pbuf);
    SOC_PBMP_FMT(config->port, pbuf);
    soc_cm_print("config->port=%s\n", pbuf);
    SOC_PBMP_FMT(config->all, pbuf);
    soc_cm_print("config->all=%s\n", pbuf);
    SOC_PBMP_FMT(config->llid, pbuf);
    soc_cm_print("config->llid=%s\n", pbuf);
    SOC_PBMP_FMT(config->pon, pbuf);
    soc_cm_print("config->pon=%s\n", pbuf);
#endif
    return BCM_E_NONE;
}

/*
 * Function
 *  bcm_tk371x_port_config_t_init
 * Purpose:
 *  Initialize a Port Configuration structure.
 * Parameters:
 * 	pconfig
 * Returns:
 *  BCM_E_XXX
 **/
void
bcm_tk371x_port_config_t_init(bcm_port_config_t *pconfig)
{
    if (pconfig != NULL){
        sal_memset(pconfig, 0, sizeof (*pconfig));
    }
}

/*
 * Function:
 *      bcm_tk371x_port_control_get
 * Description:
 *      Return the current value of the port feature identified by <type> parameter.
 * Parameters:
 *      unit - Device number
 *      port - Port number
 *      type - Identifies the port feature to be controlled
 *      value - Value of the bit field in port table
 * Return Value:
 *      BCM_E_NONE
 *      BCM_E_XXX
 * Notes:
 */
int
bcm_tk371x_port_control_get(
        int unit,
        bcm_port_t port,
        bcm_port_control_t type,
        int *value)
{
    int rv = BCM_E_INTERNAL;

#if _BCM_EA_PORT_DEBUG
	soc_cm_print("BCM API : bcm_tk371x_port_control_get(),"
			     " unit=%d, port=%d, type=%d\n", unit, port, (int)type);
#endif
	if (0 == SOC_UNIT_VALID((unit))){
		return BCM_E_UNIT;
	}
	if (0 == SOC_PORT_VALID(unit, port)){
#if _BCM_EA_PORT_DEBUG
		soc_cm_print("Return value: BCM_E_PORT, Invaild PORT : %d\n", (port));
#endif
		return BCM_E_PORT;
	}

    rv = _bcm_ea_port_control_get(unit, port, type, value);

    return rv;
}

/*
 * Function:
 *      bcm_tk371x_port_control_set
 * Description:
 *      Enable/Disable various features at the port level.
 * Parameters:
 *      unit - Device number
 *      port - Port number
 *      type - Identifies the port feature to be controlled
 *      value - Value of the bit field in port table
 * Return Value:
 *      BCM_E_NONE
 *      BCM_E_XXX
 * Notes:
 */
int
bcm_tk371x_port_control_set(
	    int unit,
	    bcm_port_t port,
	    bcm_port_control_t type,
	    int value)
{
	int rv = BCM_E_NONE;

#if _BCM_EA_PORT_DEBUG
	soc_cm_print("BCM API : bcm_tk371x_port_phy_control_get()..\n");
#endif
	if (0 == SOC_UNIT_VALID((unit))){
		return BCM_E_UNIT;
	}
	if (0 == SOC_PORT_VALID(unit, port)){
#if _BCM_EA_PORT_DEBUG
		soc_cm_print("Return BCM_E_PORT, invalid PORT : %d\n", (port));
#endif
		return BCM_E_PORT;
	}
	rv = _bcm_ea_port_control_set(unit, port, type, value);
	return rv;
}

/*
 * Function:
 *      bcm_port_duplex_get
 * Purpose:
 *      Get the port duplex settings
 * Parameters:
 *      unit - Tk371x EPON Unit #.
 *      port - Tk371x port #.
 *      duplex - (OUT) Duplex setting, one of SOC_PORT_DUPLEX_xxx
 * Returns:
 *      BCM_E_NONE
 *      BCM_E_XXX
 */
int
bcm_tk371x_port_duplex_get(
	    int unit,
	    bcm_port_t port,
	    int *duplex)
{
	int rv = BCM_E_NONE;
	int drv_act_value;

#if _BCM_EA_PORT_DEBUG
	soc_cm_print("BCM API : bcm_tk371x_port_duplex_get..\n");
#endif
	if (0 == SOC_UNIT_VALID((unit))){
		return BCM_E_UNIT;
	}
	if (0 == SOC_PORT_VALID(unit, port)){
#if _BCM_EA_PORT_DEBUG
		soc_cm_print("Return BCM_E_PORT, invalid PORT : %d\n", (port));
#endif
		return BCM_E_PORT;
	}

    rv = _bcm_ea_port_duplex_get(unit, port, &drv_act_value);
    if (rv != BCM_E_NONE){
    	return rv;
    }
    if (drv_act_value == DRV_PORT_STATUS_DUPLEX_HALF) {
    	drv_act_value = BCM_PORT_DUPLEX_HALF;
    }else{
    	drv_act_value = BCM_PORT_DUPLEX_FULL;
    }
    *duplex = drv_act_value;

#if _BCM_EA_PORT_DEBUG
    soc_cm_print("_bcm_ea_port_duplex_get\n");
    soc_cm_print("rv=%d, drv_act_value=%d, *duplex=%d\n", rv, drv_act_value, *duplex);
#endif
	return BCM_E_NONE;
}

/*
 * Function:
 *      bcm_port_duplex_set
 * Purpose:
 *      Set the port duplex settings.
 * Parameters:
 *      unit - Tk371x EPON Unit #.
 *      port - Tk371x port #.
 *      duplex - Duplex setting, one of SOC_PORT_DUPLEX_xxx
 * Returns:
 *      BCM_E_NONE
 *      BCM_E_XXX
 * Notes:
 *      Turns off autonegotiation.  Caller must make sure other forced
 *      parameters (such as speed) are set.
 */
int
bcm_tk371x_port_duplex_set(
	    int unit,
	    bcm_port_t port,
	    int duplex)
{
	int rv = BCM_E_NONE;

#if _BCM_EA_PORT_DEBUG
	soc_cm_print("BCM API : bcm_tk371x_port_duplex_set()..\n");
#endif
	if (0 == SOC_UNIT_VALID((unit))){
		return BCM_E_UNIT;
	}
	if (0 == SOC_PORT_VALID(unit, port)){
#if _BCM_EA_PORT_DEBUG
		soc_cm_print("Return BCM_E_PORT, invalid PORT : %d\n", (port));
#endif
		return BCM_E_PORT;
	}

	if (duplex != BCM_PORT_DUPLEX_FULL && duplex != BCM_PORT_DUPLEX_HALF){
#if _BCM_EA_PORT_DEBUG
		soc_cm_print("Return BCM_E_PARAM, invalid duplex : %d\n", (duplex));
#endif
		return BCM_E_PARAM;
	}
	rv = _bcm_ea_port_duplex_set(unit, port, duplex);
	if (rv != BCM_E_NONE){
		return rv;
	}
	return BCM_E_NONE;
}

/*
 * Function:
 *  bcm_tk371x_port_enable_get
 * Purpose:
 *  Gets the enable state as defined by bcm_port_enable_set()
 * Parameters:
 *  unit - EA unit #.
 *  port - EA port #.
 *  enable - (OUT) TRUE, port is enabled, FALSE port is disabled.
 * Returns:
 *  BCM_E_XXXX
 * Notes:
 *  The PHY enable holds the port enable state set by the user.
 *  The MAC enable transitions up and down automatically via linkscan
 *  even if user port enable is always up.
 */
int
bcm_tk371x_port_enable_get(
	    int unit,
	    bcm_port_t port,
	    int *enable)
{
    int         rv = BCM_E_NONE ;

#if _BCM_EA_PORT_DEBUG
	soc_cm_print("BCM API : bcm_tk371x_port_enable_get..\n");
#endif
	if (0 == SOC_UNIT_VALID((unit))){
		return BCM_E_UNIT;
	}
	if (0 == SOC_PORT_VALID(unit, port)){
#if _BCM_EA_PORT_DEBUG
		soc_cm_print("Return BCM_E_PORT, invalid PORT : %d\n", (port));
#endif
		return BCM_E_PORT;
	}

    rv = _bcm_ea_port_enable_get(unit, port, enable);
#if _BCM_EA_PORT_DEBUG
    soc_cm_print("bcm_port_enable_get: u=%d p=%d rv=%d enable=%d\n",
             unit, port, rv, *enable);
#endif
    return rv;
}

/*
 * Function:
 *  bcm_tk371x_port_enable_set
 * Purpose:
 *  Physically enable/disable the MAC/PHY on this port.
 * Parameters:
 *  unit - EA unit #.
 *  port - EA port #.
 *  enable - TRUE, port is enabled, FALSE port is disabled.
 * Returns:
 *  BCM_E_XXXX
 * Notes:
 *  If linkscan is running, it also controls the MAC enable state.
 */
int
bcm_tk371x_port_enable_set(
	    int unit,
	    bcm_port_t port,
	    int enable)
{
    int         rv = BCM_E_NONE ;
    int 		state;

#if _BCM_EA_PORT_DEBUG
	soc_cm_print("BCM API : bcm_tk371x_port_enable_set.., unit=%d\n", unit);
#endif
	if (0 == SOC_UNIT_VALID((unit))){
		return BCM_E_UNIT;
	}
	if (0 == SOC_PORT_VALID(unit, port)){
#if _BCM_EA_PORT_DEBUG
		soc_cm_print("Return BCM_E_PORT, invalid PORT : %d\n", (port));
#endif
		return BCM_E_PORT;
	}
	/* check the enable param is valid?*/
    if ((enable == 0) || (enable == 1)){
    	state = enable;
    }
    else{
#if _BCM_EA_PORT_DEBUG
		soc_cm_print("Return BCM_E_PARAM, invalid value : %d\n", (enable));
#endif
    	return BCM_E_PARAM;
    }
    rv = _bcm_ea_port_enable_set(unit, port, state);
#if _BCM_EA_PORT_DEBUG
    soc_cm_print("_bcm_ea_port_enable_set:unit=%d port=%d rv=%d enable=%d\n",
             unit, port, rv, enable);
#endif
    return rv;
}


/*
 * Function:
 *  bcm_tk371x_port_frame_max_get
 * Description:
 *  Set the maximum receive frame size for the port
 * Parameters:
 *  unit - Device number
 *  port - Port number
 *  size - Maximum frame size in bytes
 * Return Value:
 *  BCM_E_XXX
 * Notes:
 *      Depending on chip or port type the actual maximum receive frame size
 *      might be slightly higher.
 *
 *      For GE ports that use 2 separate MACs (one for GE and another one for
 *      10/100 modes) the function returns the maximum rx frame size set for
 *      the current mode.
 */
int
bcm_tk371x_port_frame_max_get(
	    int unit,
	    bcm_port_t port,
	    int *size)
{
	int rv = BCM_E_NONE;

#if _BCM_EA_PORT_DEBUG
	soc_cm_print("BCM API : bcm_tk371x_port_frame_max_get.., unit=%d\n", unit);
#endif
	if (0 == SOC_UNIT_VALID((unit))){
		return BCM_E_UNIT;
	}
	if (0 == SOC_PORT_VALID(unit, port)){
#if _BCM_EA_PORT_DEBUG
		soc_cm_print("Return BCM_E_PORT, invalid PORT : %d\n", (port));
#endif
		return BCM_E_PORT;
	}

    rv = _bcm_ea_port_frame_max_get(unit, port, size);

#if _BCM_EA_PORT_DEBUG
    soc_cm_print("_bcm_ea_port_frame_max_get:unit=%d port=%d rv=%d size=%d\n",
             unit, port, rv,*size);
#endif
	return rv;
}

/*
 * Function:
 *  bcm_tk371x_port_frame_max_set
 * Description:
 *  Set the maximum receive frame size for the port
 * Parameters:
 *  unit - Device number
 *  port - Port number
 *  size - Maximum frame size in bytes
 * Return Value:
 *  BCM_E_XXX
 * Notes:
 *      Depending on chip or port type the actual maximum receive frame size
 *      might be slightly higher.
 *
 *      It looks like this operation is performed the same way on all the chips
 *      and the only depends on the port type.
 */
int
bcm_tk371x_port_frame_max_set(
	    int unit,
	    bcm_port_t port,
	    int size)
{
	int rv = BCM_E_NONE;

#if _BCM_EA_PORT_DEBUG
	soc_cm_print("BCM API : bcm_tk371x_port_frame_max_set.., unit=%d\n", unit);
#endif
	if (0 == SOC_UNIT_VALID((unit))){
		return BCM_E_UNIT;
	}
	if (0 == SOC_PORT_VALID(unit, port)){
#if _BCM_EA_PORT_DEBUG
		soc_cm_print("Return BCM_E_PORT, invalid PORT : %d\n", (port));
#endif
		return BCM_E_PORT;
	}

    rv = _bcm_ea_port_frame_max_set(unit, port, size);
#if _BCM_EA_PORT_DEBUG
    soc_cm_print("_bcm_ea_port_frame_max_set:unit=%d port=%d rv=%d size=%d\n",
             unit, port, rv, size);
#endif
	return rv;
}

/*
 * Each field in the bcm_port_info_t structure has a corresponding
 * mask bit to control whether to get or set that value during the
 * execution of the bcm_port_selective_get/_set functions.
 * The OR of all requested masks should be stored in the action_mask
 * field of the bcm_port_info_t before calling the functions.
 */


/*
 * Routines to set or get port parameters in one call.
 *
 * The "action mask" indicates which values should be set/gotten.
 */


/*
 * Function:
 *  bcm_tk371x_port_info_get
 * Purpose:
 *  Get all information on the port
 * Parameters:
 *  unit - EA unit #
 *  port - EA port #
 *  info - Pointer to structure in which to save values
 * Returns:
 *  BCM_E_XXX
 */
int
bcm_tk371x_port_info_get(
	    int unit,
	    bcm_port_t port,
	    bcm_port_info_t *info)
{

	soc_cm_print("BCM API : bcm_tk371x_port_info_save..\n");
	if (0 == SOC_UNIT_VALID((unit))){
		return BCM_E_UNIT;
	}
	if (0 == SOC_PORT_VALID(unit, port)){
		soc_cm_print("PORT : %d\n", (port));
		return BCM_E_PORT;
	}
    info->action_mask = 0;
    info->action_mask |= BCM_PORT_ATTR_ENABLE_MASK;
    info->action_mask |= BCM_PORT_ATTR_LINKSTAT_MASK;
    info->action_mask |= BCM_PORT_ATTR_AUTONEG_MASK;
    info->action_mask |= BCM_PORT_ATTR_SPEED_MASK;
    info->action_mask |= BCM_PORT_ATTR_SPEED_MAX_MASK;
    info->action_mask |= BCM_PORT_ATTR_DUPLEX_MASK;
    info->action_mask |= BCM_PORT_ATTR_LEARN_MASK;
    info->action_mask |= BCM_PORT_ATTR_LOOPBACK_MASK;
    info->action_mask |= BCM_PORT_ATTR_INTERFACE_MASK;
    info->action_mask |= BCM_PORT_ATTR_PAUSE_TX_MASK;
    info->action_mask |= BCM_PORT_ATTR_PAUSE_RX_MASK;
    info->action_mask |= BCM_PORT_ATTR_LOCAL_ADVERT_MASK;
    info->action_mask |= BCM_PORT_ATTR_ABILITY_MASK;
    info->action_mask |= BCM_PORT_ATTR_REMOTE_ADVERT_MASK;
    info->action_mask |= BCM_PORT_ATTR_FRAME_MAX_MASK;
    info->action_mask |= BCM_PORT_ATTR_MEDIUM_MASK;
    info->action_mask2 = 0;
    info->action_mask2 |= BCM_PORT_ATTR2_PORT_ABILITY;

    return _bcm_tk371x_port_selective_get(unit, port, info);
}

/*
 * Function:
 *  bcm_tk371x_port_info_restore
 * Purpose:
 *  Restore port settings saved by info_save
 * Parameters:
 *  unit - EA unit #
 *  port - EA port #
 *  info - Pointer to structure with info from port_info_save
 * Returns:
 *  BCM_E_XXX
 * Notes:
 *  bcm_port_info_save has done all the work.
 *  We just call port_selective_set.
 */

/*
 * Function:
 *  bcm_tk371x_port_info_save
 * Purpose:
 *  Save the current settings of a port
 * Parameters:
 *  unit - EA unit #
 *  port - EA port #
 *  info - Pointer to structure in which to save values
 * Returns:
 *  BCM_E_XXX
 * Notes:
 *  The action_mask will be adjusted so that the
 *  proper values will be set when a restore is made.
 *  This mask should not be altered between these calls.
 */
int
bcm_tk371x_port_info_save(
	    int unit,
	    bcm_port_t port,
	    bcm_port_info_t *info)
{
	soc_cm_debug(DK_PORT, "BCM API : bcm_tk371x_port_info_save..\n");
	if (0 == SOC_UNIT_VALID((unit))){
		soc_cm_debug(DK_PORT, "UNIT : %d\n", (unit));
		return BCM_E_UNIT;
	}
	if (0 == SOC_PORT_VALID(unit, port)){
		soc_cm_debug(DK_PORT, "PORT : %d\n", (port));
		return BCM_E_PORT;
	}

    info->action_mask = BCM_PORT_ATTR_ALL_MASK;

    soc_cm_debug(DK_PORT, "BCM API : bcm_robo_port_info_save()..\n");
    BCM_IF_ERROR_RETURN(_bcm_tk371x_port_selective_get(unit, port, info));

    return BCM_E_NONE;
}


/*
 * Function:
 *  bcm_tk371x_port_info_set
 * Purpose:
 *  Set all information on the port
 * Parameters:
 *  unit - EA unit #
 *  port - EA port #
 *  info - Pointer to structure in which to save values
 * Returns:
 *  BCM_E_XXX
 * Notes:
 *  Checks if AN is on, and if so, clears the
 *  proper bits in the action mask.
 */
int
bcm_tk371x_port_info_set(
	    int unit,
	    bcm_port_t port,
	    bcm_port_info_t *info)
{
	int rv = BCM_E_NONE;

	soc_cm_debug(DK_PORT, "BCM API : bcm_tk371x_port_info_set..\n");
	if (0 == SOC_UNIT_VALID((unit))){
		soc_cm_debug(DK_PORT, "UNIT : %d\n", (unit));
		return BCM_E_UNIT;
	}
	if (0 == SOC_PORT_VALID(unit, port)){
		soc_cm_debug(DK_PORT, "PORT : %d\n", (port));
		return BCM_E_PORT;
	}

    rv = bcm_tk371x_port_info_restore(unit, port, info);

	return rv;
}

/* Initialize a Port Configuration structure. */
/*
 * Function:
 *  bcm_tk371x_port_info_t_init
 * Purpose:
 *  Set all information on the port
 * Parameters:
 *  info - Pointer to structure in which to save values
 * Returns:
 *  BCM_E_XXX
 * Notes:
 *  Checks if AN is on, and if so, clears the
 *  proper bits in the action mask.
 */
void
bcm_tk371x_port_info_t_init(bcm_port_info_t *info)
{
	if (NULL != info){
		sal_memset(info, 0, sizeof(*info));
	}
}

/* Module one-time initialization routine */

/*
 * Function:
 *      bcm_tk371x_port_init
 * Purpose:
 *      Initialize the PORT interface layer for the specified SOC device.
 * Parameters:
 *      unit - EA unit number.
 * Returns:
 *      BCM_E_NONE - success (or already initialized)
 *      BCM_E_MEMORY - failed to allocate required memory.
 * Notes:
 *      All ports set in disabled state.
 *      Default PVID initialized.
 */
int
bcm_tk371x_port_init(int unit)
{
	int rv = BCM_E_NONE;

	if (0 == SOC_UNIT_VALID(unit)){
		return BCM_E_UNIT;
	}
#if _BCM_EA_PORT_DEBUG
	soc_cm_print("bcm_tk371x_port_init, unit = %d\n", unit);
#endif
	rv = _bcm_tk371x_port_detach(unit);

	return rv;
}

/*
 * Function:
 *  bcm_tk371x_port_learn_get
 * Purpose:
 *  Get the ARL hardware learning options for this port.
 *  This defines what the hardware will do when a packet
 *  is seen with an unknown address.
 * Parameters:
 *  unit - EA Unit #.
 *  port - EA port #.
 *  flags - (OUT) Logical OR of BCM_PORT_LEARN_xxx flags
 * Returns:
 *  BCM_E_NONE
 *  BCM_E_XXX
 */
int
bcm_tk371x_port_learn_get(
		int unit,
	    bcm_port_t port,
	    uint32 *flags)
{
#if _BCM_EA_PORT_DEBUG
	soc_cm_print("BCM API : bcm_tk371x_port_learn_get..\n");
#endif
	if (0 == SOC_UNIT_VALID((unit))){
		return BCM_E_UNIT;
	}
	if (0 == SOC_PORT_VALID(unit, port)){
#if _BCM_EA_PORT_DEBUG
		soc_cm_print("Return BCM_E_PORT, invalid PORT : %d\n", (port));
#endif
		return BCM_E_PORT;
	}

	return _bcm_ea_port_learn_get(unit, port, flags);
}

/*
 * Function:
 *  bcm_tk371x_port_learn_modify
 * Purpose:
 *  Modify the port learn flags, adding add and removing remove flags.
 * Parameters:
 *  unit - EA Unit #.
 *  port - EA port #.
 *  add  - Flags to set.
 *      remove - Flags to clear.
 * Returns:
 *  BCM_E_NONE
 *  BCM_E_XXX
 */
int
bcm_tk371x_port_learn_modify(
	    int unit,
	    bcm_port_t port,
	    uint32 add,
	    uint32 remove)
{
#if _BCM_EA_PORT_DEBUG
	soc_cm_print("BCM API : bcm_tk371x_port_learn_modify..\n");
#endif
	if (0 == SOC_UNIT_VALID((unit))){
		return BCM_E_UNIT;
	}
	if (0 == SOC_PORT_VALID(unit, port)){
#if _BCM_EA_PORT_DEBUG
		soc_cm_print("Return BCM_E_PORT, invalid PORT : %d\n", (port));
#endif
		return BCM_E_PORT;
	}
	return _bcm_ea_port_learn_modify(unit, port, add, remove);
}

/*
 * Function:
 *  bcm_tk371x_port_learn_set
 * Purpose:
 *  Set the ARL hardware learning options for this port.
 *  This defines what the hardware will do when a packet
 *  is seen with an unknown address.
 * Parameters:
 *  unit - EA Unit #.
 *  port - EA port #.
 *  flags - Logical OR of BCM_PORT_LEARN_xxx flags
 * Returns:
 *  BCM_E_NONE
 *  BCM_E_XXX
 */
int
bcm_tk371x_port_learn_set(
	    int unit,
	    bcm_port_t port,
	    uint32 flags)
{
#if _BCM_EA_PORT_DEBUG
	soc_cm_print("BCM API : bcm_tk371x_port_learn_set..\n");
#endif
	if (0 == SOC_UNIT_VALID((unit))){
		return BCM_E_UNIT;
	}
	if (0 == SOC_PORT_VALID(unit, port)){
#if _BCM_EA_PORT_DEBUG
		soc_cm_print("Return BCM_E_PORT, invalid PORT : %d\n", (port));
#endif
		return BCM_E_PORT;
	}
	return _bcm_ea_port_learn_set(unit, port, flags);
}

/*
 * Function:
 *  bcm_tk371x_port_link_status_get
 * Purpose:
 *  Return current Link up/down status, queries linkscan, if unable to
 *  retrieve status queries the PHY.
 * Parameters:
 *  unit - EA Unit #.
 *  port - EA port #.
 *  up - (OUT) Boolean value, FALSE for link down and TRUE for link up
 * Returns:
 *  BCM_E_NONE
 *  BCM_E_XXX
 */
int
bcm_tk371x_port_link_status_get(
	    int unit,
	    bcm_port_t port,
	    int *status)
{
	int rv = BCM_E_INTERNAL;

#if _BCM_EA_PORT_DEBUG
	soc_cm_print("BCM API : bcm_tk371x_port_link_status_get..\n");
#endif
	if (0 == SOC_UNIT_VALID((unit))){
		return BCM_E_UNIT;
	}
	if (0 == SOC_PORT_VALID(unit, port)){
#if _BCM_EA_PORT_DEBUG
	soc_cm_print("bcm_tk371x_port_link_status_get Return value BCM_E_PORT, invalid port=%d\n", port);
#endif
		return BCM_E_PORT;
	}

	rv = _bcm_ea_port_link_status_get(unit, port, status);

	return rv;
}

/*
 * Function:
 *     bcm_tk371x_port_phy_control_get
 * Description:
 *     Set PHY specific properties
 * Parameters:
 *     unit        device number
 *     port        port number
 *     type        configuration type
 *     value       value for the configuration
 * Return:
 *     BCM_E_XXX
 */
int
bcm_tk371x_port_phy_control_get(
	    int unit,
	    bcm_port_t port,
	    bcm_port_phy_control_t type,
	    uint32 *value)
{
    int rv = BCM_E_INTERNAL;

	soc_cm_debug(DK_PORT, "BCM API : bcm_tk371x_port_phy_control_get..\n");
	if (0 == SOC_UNIT_VALID((unit))){
		soc_cm_debug(DK_PORT, "UNIT : %d\n", (unit));
		return BCM_E_UNIT;
	}
	if (0 == SOC_PORT_VALID(unit, port)){
		soc_cm_debug(DK_PORT, "PORT : %d\n", (port));
		return BCM_E_PORT;
	}

    rv = _bcm_ea_port_phy_control_get(unit, port, type, value);

    return rv;
}

/*
 * Function:
 *     bcm_tk371x_port_phy_control_set
 * Description:
 *     Set PHY specific properties
 * Parameters:
 *     unit        device number
 *     port        port number
 *     type        configuration type
 *     value       new value for the configuration
 * Return:
 *     BCM_E_XXX
 */
int
bcm_tk371x_port_phy_control_set(
	    int unit,
	    bcm_port_t port,
	    bcm_port_phy_control_t type,
	    uint32 value)
{
    int rv = BCM_E_INTERNAL;

	soc_cm_debug(DK_PORT, "BCM API : bcm_tk371x_port_phy_control_set..\n");
	if (0 == SOC_UNIT_VALID((unit))){
		soc_cm_debug(DK_PORT, "UNIT : %d\n", (unit));
		return BCM_E_UNIT;
	}
	if (0 == SOC_PORT_VALID(unit, port)){
		soc_cm_debug(DK_PORT, "PORT : %d\n", (port));
		return BCM_E_PORT;
	}

    rv = _bcm_ea_port_phy_control_set(unit, port, type, value);
    return rv;
}

/*
 * Function:
 *  bcm_tk371x_port_speed_get
 * Purpose:
 *  Getting the speed of the port
 * Parameters:
 *  unit - EA Unit #.
 *  port - EA port #.
 *  speed - (OUT) Value in megabits/sec (10, 100, etc)
 * Returns:
 *  BCM_E_NONE
 *  BCM_E_XXX
 * Notes:
 *  If port is in MAC loopback, the speed of the loopback is returned.
 *  On chips with a PHYMOD field:
 *      If PHYMOD=0, the speed is hardwired to 100Mb/s.
 *      If PHYMOD=1, the speed is obtained directly from the PHY.
 *  In either case, FE_SUPP.SPEED is completely ignored.
 */
int
bcm_tk371x_port_speed_get(
	    int unit,
	    bcm_port_t port,
	    int *speed)
{
    int     rv = BCM_E_INTERNAL;
    uint32  drv_value = 0U;

#if _BCM_EA_PORT_DEBUG
	soc_cm_print("BCM API : bcm_tk371x_port_speed_get..\n");
#endif
	if (0 == SOC_UNIT_VALID((unit))){
		return BCM_E_UNIT;
	}
	if (0 == SOC_PORT_VALID(unit, port)){
#if _BCM_EA_PORT_DEBUG
		soc_cm_print("Return BCM_E_PORT, invalid=%d\n", port);
#endif
		return BCM_E_PORT;
	}

    rv = _bcm_ea_port_speed_get(unit, port, (int*)&drv_value);

    *speed = (drv_value == DRV_PORT_STATUS_SPEED_10M) ? 10 :
                (drv_value == DRV_PORT_STATUS_SPEED_100M) ? 100 :
                (drv_value == DRV_PORT_STATUS_SPEED_1G) ? 1000 :
                (drv_value == DRV_PORT_STATUS_SPEED_2500M) ? 2500 :
                (drv_value == DRV_PORT_STATUS_SPEED_10G) ? 10000 :
                0;
#if _BCM_EA_PORT_DEBUG
    soc_cm_print("_bcm_ea_port_speed_get:unit=%d port=%d rv=%d speed=%d\n",
             unit, port, rv, *speed);
#endif
	return rv;
}


int bcm_tk371x_port_speed_max(
		int unit,
		bcm_port_t port,
		int *speed)
{
    if (0 == SOC_UNIT_VALID((unit))){
    	return BCM_E_UNIT;
    }
    if (0 == SOC_PORT_VALID(unit, port)){
#if _BCM_EA_PORT_DEBUG
        soc_cm_print("Return value: BCM_E_PORT: invalid PORT : %d\n", (port));
#endif
        return BCM_E_PORT;
    }
	if (port < _BCM_TK371X_UNI_PORT_BASE || port >= _BCM_TK371X_LLID_PORT_BASE){
		return BCM_E_UNAVAIL;
	}
	return BCM_E_UNAVAIL;
}
/*
 * Function:
 *  bcm_tk371x_port_speed_set
 * Purpose:
 *  Getting the maximum speed of the port
 * Parameters:
 *  unit - EA Unit #.
 *  port - EA port #.
 *  speed - (OUT) Value in megabits/sec (10, 100, etc)
 * Returns:
 *  BCM_E_NONE
 *  BCM_E_XXX
 */
int
bcm_tk371x_port_speed_set(
	    int unit,
	    bcm_port_t port,
	    int speed)
{
	int	rv = BCM_E_INTERNAL;

#if _BCM_EA_PORT_DEBUG
	soc_cm_print("BCM API : bcm_tk371x_port_speed_get..\n");
#endif
	if (0 == SOC_UNIT_VALID((unit))){
		return BCM_E_UNIT;
	}
	if (0 == SOC_PORT_VALID(unit, port)){
#if _BCM_EA_PORT_DEBUG
		soc_cm_print("Return BCM_E_PORT, invalid=%d\n", port);
#endif
		return BCM_E_PORT;
	}
	rv = _bcm_ea_port_speed_set(unit, port, speed);
#if _BCM_EA_PORT_DEBUG
    soc_cm_print("_bcm_ea_port_speed_set:unit=%d port=%d rv=%d speed=%d\n",
             unit, port, rv, speed);
#endif
	return rv;
}

int bcm_tk371x_port_probe(
		int unit,
		bcm_pbmp_t ibp,
		bcm_pbmp_t *obp)
{
	bcm_port_t port;
	int okay = 0;

	soc_cm_debug(DK_PORT, "BCM API : bcm_tk371x_port_probe()..\n");
	BCM_PBMP_CLEAR(*obp);

	PBMP_ITER(ibp, port){
		/* do port_probe process */
		bcm_tk371x_port_link_status_get(unit, port, &okay);
		if (okay){
			BCM_PBMP_PORT_ADD(*obp, port);
		}
	}
	return BCM_E_NONE;
}

int
bcm_tk371x_port_flood_block_get(
		int unit,
		bcm_port_t iport,
		bcm_port_t oport,
		uint32 *value)
{
    soc_cm_debug(DK_PORT, "BCM API : bcm_tk371x_port_flood_block_get()..\n");
    *value = 0;

	return BCM_E_UNAVAIL;
}

int
bcm_tk371x_port_flood_block_set(
		int unit,
		bcm_port_t iport,
		bcm_port_t oport,
		uint32 value)
{
	return BCM_E_UNAVAIL;
}


int
bcm_tk371x_port_info_restore(
	    int unit,
	    bcm_port_t port,
	    bcm_port_info_t *info)
{
    uint32      mask = 0;

	soc_cm_debug(DK_PORT, "BCM API : bcm_tk371x_port_info_restore..\n");
	if (0 == SOC_UNIT_VALID((unit))){
		return BCM_E_UNIT;
	}
	if (0 == SOC_PORT_VALID(unit, port)){
		soc_cm_debug(DK_PORT, "PORT : %d\n", (port));
		return BCM_E_PORT;
	}

    mask = info->action_mask;

    if (mask & BCM_PORT_ATTR_ENABLE_MASK){
    	bcm_tk371x_port_enable_set(unit, port, info->enable);
    }

    if (mask & BCM_PORT_ATTR_AUTONEG_MASK){
    	bcm_tk371x_port_autoneg_set(unit, port, info->autoneg);
    }

    if (mask & BCM_PORT_ATTR_SPEED_MASK){
    	bcm_tk371x_port_speed_set(unit, port, info->speed);
    }

    if (mask & BCM_PORT_ATTR_LEARN_MASK){
    	bcm_tk371x_port_learn_set(unit, port, info->learn);
    }

    /*
     * Set loopback mode before setting the speed/duplex, since it may
     * affect the allowable values for speed/duplex.
     */
    if (mask & BCM_PORT_ATTR_LOOPBACK_MASK){
        bcm_tk371x_port_control_set(unit, port,
        		bcmPortControlEthPortLoopbackAlarmState, info->loopback);
    }

    if (mask & BCM_PORT_ATTR_INTERFACE_MASK){
    	bcm_tk371x_port_interface_set(unit, port, info->interface);
    }

    if ((mask & BCM_PORT_ATTR_PAUSE_TX_MASK) &&
    		(mask & BCM_PORT_ATTR_PAUSE_RX_MASK)){
    	bcm_tk371x_port_pause_set(unit, port, info->pause_tx, info->pause_tx);
    }

    if (mask & BCM_PORT_ATTR_LOCAL_ADVERT_MASK){
    	bcm_tk371x_port_advert_set(unit, port, info->local_advert);
    }

    if (mask & BCM_PORT_ATTR_DUPLEX_MASK){
        bcm_tk371x_port_duplex_set(unit, port, info->duplex);
    }

    if (mask & BCM_PORT_ATTR_FRAME_MAX_MASK) {
        bcm_tk371x_port_frame_max_set(unit, port, info->frame_max);
    }

	return BCM_E_NONE;
}



int
_bcm_tk371x_port_selective_get(
		int unit,
		bcm_port_t port,
		bcm_port_info_t *info)
{
    uint32      mask = 0;
    uint32 		mask2 = 0;

#if _BCM_EA_PORT_DEBUG
    soc_cm_print("BCM API : _bcm_tk371x_port_selective_get()..\n");
#endif
    if (port <= _BCM_TK371X_UNI_PORT_BASE ||
    		port >= _BCM_TK371X_LLID_PORT_BASE){
    	return BCM_E_UNAVAIL;
    }
    mask = info->action_mask;
    mask2 = info->action_mask2;

    if (mask & BCM_PORT_ATTR_ENABLE_MASK){
    	bcm_tk371x_port_enable_get(unit, port, &info->enable);
    }

    if (mask & BCM_PORT_ATTR_LINKSTAT_MASK){
    	bcm_tk371x_port_link_status_get(unit, port, &info->linkstatus);
    }

    if (mask & BCM_PORT_ATTR_AUTONEG_MASK){
    	bcm_tk371x_port_autoneg_get(unit, port, &info->autoneg);
    }

    if (mask & BCM_PORT_ATTR_SPEED_MASK){
    	bcm_tk371x_port_speed_get(unit, port, &info->speed);
    }

    if (mask & BCM_PORT_ATTR_DUPLEX_MASK){
    	bcm_tk371x_port_duplex_get(unit, port, &info->duplex);
    }

    if (mask & BCM_PORT_ATTR_LEARN_MASK){
    	bcm_tk371x_port_learn_get(unit, port, &info->learn);
    }

    if (mask & BCM_PORT_ATTR_LOOPBACK_MASK){
    	bcm_tk371x_port_loopback_get(unit, port, &info->loopback);
    }

    if (mask & BCM_PORT_ATTR_INTERFACE_MASK){
    	bcm_tk371x_port_interface_get(unit, port, &info->interface);
    }

    if ((mask & BCM_PORT_ATTR_PAUSE_TX_MASK) &&
    		(mask & BCM_PORT_ATTR_PAUSE_RX_MASK)){
    	bcm_tk371x_port_pause_get(unit, port, &info->pause_tx, &info->pause_rx);
    }

    if (mask & BCM_PORT_ATTR_LOCAL_ADVERT_MASK){
    	bcm_tk371x_port_advert_get(unit, port, &info->local_advert);
    }

    if (mask & BCM_PORT_ATTR2_PORT_ABILITY){
    	bcm_tk371x_port_ability_local_get(unit, port, &info->local_ability);
    }

    if (mask & BCM_PORT_ATTR_REMOTE_ADVERT_MASK){
    	bcm_tk371x_port_advert_remote_get(unit, port, &info->remote_advert);
    }

    if ((mask & BCM_PORT_ATTR2_PORT_ABILITY) &&
    		(mask & BCM_PORT_ATTR_REMOTE_ADVERT_MASK)){
    	bcm_tk371x_port_ability_remote_get(unit, port, &info->remote_ability);
    }

    if (mask & BCM_PORT_ATTR_SPEED_MAX){
    	bcm_tk371x_port_speed_max(unit, port, &info->speed_max);
    }

    if (mask & BCM_PORT_ATTR_ABILITY_MASK){
    	bcm_tk371x_port_ability_get(unit, port, &info->ability);
    }

    if ((mask & BCM_PORT_ATTR_ABILITY_MASK) &&
    		(mask & BCM_PORT_ATTR2_PORT_ABILITY)){
    	bcm_tk371x_port_ability_local_get(unit, port, &info->local_ability);
    }

    if (mask & BCM_PORT_ATTR_FRAME_MAX_MASK){
    	bcm_tk371x_port_frame_max_get(unit, port, &info->frame_max);
    }

    if (mask & BCM_PORT_ATTR_MEDIUM_MASK){
    	bcm_tk371x_port_medium_get(unit, port, &info->medium);
    }
    return BCM_E_NONE;
}

int bcm_tk371x_port_pon_info_get(
		int unit,
		bcm_port_t port,
		bcm_port_pon_info_t *pon)
{
	int rv = BCM_E_NONE;
	TkEponRegState pon_state;

#if _BCM_EA_PORT_DEBUG
	int i = 0;

	soc_cm_print("bcm_tk371x_port_pon_info_get...\n");
#endif
	if (_BCM_TK371X_PON_PORT_BASE != port){
#if _BCM_EA_PORT_DEBUG
		soc_cm_print("Return BCM_E_PORT, invalid port=%d\n", port);
#endif
		return BCM_E_PORT;
	}

	rv = _soc_ea_pon_reg_status_get(unit, port, &pon_state);

	if (rv != OK){
#if _BCM_EA_PORT_DEBUG
		soc_cm_print("_soc_ea_pon_reg_status_get Return BCM_E_INTERNAL, invalid value=%d\n", rv);
#endif
		return BCM_E_INTERNAL;
	}
	pon->enable = pon_state.connection;
	pon->linkstatus = pon_state.Oam_link_established;
	pon->llid = pon_state.ONU_LLID;
	pon->loopback = pon_state.Pon_Loopback;
	pon->oam_discovery_status = pon_state.Oam_link_established;
	sal_memcpy((void*)(pon->olt_mac_addr),
			(void*)pon_state.Olt_MAC_addr, sizeof(bcm_mac_t));
#if _BCM_EA_PORT_DEBUG
    soc_cm_print("_soc_ea_pon_reg_status_get:unit=%d port=%d rv=%d\n",
             unit, port, rv);
    soc_cm_print("pon->enable=%d\n", pon->enable);
	soc_cm_print("pon->linkstatus=%d\n", pon->linkstatus);
	soc_cm_print("pon->llid=%d\n", pon->llid);
	soc_cm_print("pon->loopback=%d\n", pon->loopback);
	soc_cm_print("pon->oam_discovery_status=%d\n", pon->oam_discovery_status);
	soc_cm_print("pon->olt_mac_addr=");
	for (i = 0; i < sizeof(bcm_mac_t); i++){
		soc_cm_print("%02X", pon->olt_mac_addr[i]);
	}
	soc_cm_print("\n");
#endif
	return BCM_E_NONE;;
}

int bcm_tk371x_port_pon_info_set(
		int unit,
		bcm_port_t port,
		bcm_port_pon_info_t *pon)
{
	int rv = BCM_E_NONE;

#if _BCM_EA_PORT_DEBUG
	soc_cm_print("bcm_tk371x_port_pon_info_set...\n");
#endif
	if (0 == SOC_UNIT_VALID((unit))){
		return BCM_E_UNIT;
	}
	if (_BCM_TK371X_PON_PORT_BASE != port){
#if _BCM_EA_PORT_DEBUG
		soc_cm_print("Return BCM_E_PORT, invalid port=%d\n", port);
#endif
		return BCM_E_PORT;
	}
	if (pon->enable != 0 && pon->enable != 1){
#if _BCM_EA_PORT_DEBUG
    soc_cm_print("Return BCM_E_PARAM, invalid value is %d\n", pon->enable);
#endif
		return BCM_E_PARAM;
	}
	rv = TkExtOamSetEponAdmin(unit, port, pon->enable);
#if _BCM_EA_PORT_DEBUG
    soc_cm_print("TkExtOamSetEponAdmin:unit=%d port=%d rv=%d, pon->enable=%d\n",
             unit, port, rv, pon->enable);
#endif
    if (rv != OK){
    	return BCM_E_INTERNAL;
    }
	return BCM_E_NONE;
}


int _bcm_tk371x_port_detach(int unit)
{
	return _bcm_ea_port_detach(unit);
}
